/**
 * copyright (c) 2017-2023 厦门风领科技有限公司
 * https://www.fengling.cn/
 * 
 * 引擎扩展
 * zengbinsi
 * 2020-08-26
 * 2023-10-23 15:39:07
 */


// ==============================================================================
// 扩展cc.Node
// ==============================================================================


if (!CC_EDITOR) {
    cc.Node.prototype._instantiate = function (cloned, isSyncedNode) {
        if (!cloned) {
            cloned = cc.instantiate._clone(this, this);
            // 拓展处理缓存资源的问题 zengbinsi by 20221129
            const comps = cloned.getComponentsInChildren('MonoBehavior');
            for (let i = 0; i < comps.length; i++) {
                comps[i].onInstantiateToInit && comps[i].onInstantiateToInit();
            }
        }
        cloned._parent = null;
        cloned._onBatchCreated(isSyncedNode);

        return cloned;
    };
}


if (cc.sys.isNative) {
    window.__bundleLoadingTag__ = {};
    const REGEX = /^\w+:\/\/.*/;
    const __loadBundle = cc.assetManager.loadBundle.bind(cc.assetManager);
    cc.assetManager.loadBundle = ((bundleName, opt, callback, isLocalFirst) => {
        if (window['__clearCache']) {
            return gg.warn('game clear cache.');
        }
        window.__bundleLoadingTag__[bundleName] = 0;
        if (typeof opt === 'function' && !callback) {
            callback = opt;
            opt = {};
        }

        const bundleCache = cc.assetManager.getBundle(bundleName);
        if (bundleCache) {
            return callback && callback(null, bundleCache);
        }

        if (cc.sys.isNative) {
            const cacheDir = `${cc.assetManager.cacheManager.cacheDir}/${bundleName}`;
            opt = opt || {};
            if (!isLocalFirst && (opt.version ? jsb.fileUtils.isFileExist(`${cacheDir}/config.${opt.version}.json`) : jsb.fileUtils.isDirectoryExist(cacheDir))) {
                // 如果缓存里有，优先加载缓存
                const remoteBundleHost = cc.sys.localStorage.getItem('remoteBundleHost') || 'remote';
                const url = `${remoteBundleHost}/${bundleName}`.replace(/cocos-bundle\/[0-9|.]*\/remote\//, 'cocos-bundle/cur_version/remote/');
                // gg.log('first load remote bundle:', url);
                return __loadBundle(url, opt, (err, res) => {
                    if (err) {
                        return cc.assetManager.loadBundle(bundleName, opt, callback, true);
                    }
                    // gg.log('load bundle successed:', bundleName, res.base);
                    window.__bundleLoadingTag__[bundleName] = 1;
                    callback && callback(null, res);
                });
            }
        }

        try {
            // gg.log('load local bundle:', bundleName);
            return __loadBundle(bundleName, opt, (err, res) => {
                if (err) {
                    if (REGEX.test(bundleName)) {
                        gg.warn('load bundle callback error:', bundleName);

                        gg.sendEvent('load_bundle_err', { bundle_name: bundleName, error: typeof err == 'string' ? err : (err && JSON.stringify(err)), bundle_tag: '1' });
                        return callback && callback(err);
                    } else {
                        const remoteBundleHost = cc.sys.localStorage.getItem('remoteBundleHost') || 'remote';
                        const url = `${remoteBundleHost}/${bundleName}`.replace(/cocos-bundle\/[0-9|.]*\/remote\//, 'cocos-bundle/cur_version/remote/');
                        // gg.warn('load remote bundle:', url);
                        return __loadBundle(url, opt, callback);
                    }
                }

                // gg.log('load bundle successed:', bundleName, res.base);
                window.__bundleLoadingTag__[bundleName] = 1;
                callback && callback(null, res);
            });
        } catch (error) {
            if (REGEX.test(bundleName)) {
                gg.warn('load bundle failed:', bundleName, gg.stringifyJSON(error));
                gg.sendEvent('load_bundle_err', { bundle_name: bundleName, error: typeof err == 'string' ? err : (err && JSON.stringify(err)), bundle_tag: "2" });
                callback && callback(error);
            } else {
                const remoteBundleHost = cc.sys.localStorage.getItem('remoteBundleHost') || 'remote';
                const url = `${remoteBundleHost}/${bundleName}`.replace(/cocos-bundle\/[0-9|.]*\/remote\//, 'cocos-bundle/cur_version/remote/');
                // gg.log('load remote bundle:', url);
                return __loadBundle(url, opt, callback);
            }
        }
    });
} else {

    const projectPathMap = {
        bundles: [],
        maps: {}
    };

    cc.assetManager['getProjectPathMap'] = () => {
        for (const key in cc.assetManager.bundles._map) {
            bundleEx(cc.assetManager.bundles._map[key]);
        }
        return projectPathMap;
    };

    const bundleEx = (bundle) => {
        if (projectPathMap.bundles.indexOf(bundle.name) === -1 && bundle._config && bundle._config.assetInfos && bundle._config.assetInfos._map) {
            projectPathMap.bundles.push(bundle.name);
            for (const key in bundle._config.assetInfos._map) {
                projectPathMap.maps[key] = `${bundle.name}:${bundle._config.assetInfos._map[key].path}`;
            }
        }


        return bundle;
    };

    const __loadBundle = cc.assetManager.loadBundle.bind(cc.assetManager);
    cc.assetManager.loadBundle = (bundleName, opt, callback) => {
        if (typeof opt === 'function') {
            callback = opt;
            opt = {};
        }

        return __loadBundle(bundleName, opt, (err, res) => {
            if (res) {
                res = bundleEx(res);
            }

            callback && callback(err, res);
        });
    };
}


// ==============================================================================
// 扩展Audio
// ==============================================================================
// class PolyfillAudioManager {
//     _players = [];
//     _playingAudios = [];
//     maxAudioChannel = 10;

//     removePlaying(oneShotAudio) {
//         let index = this._playingAudios.indexOf(oneShotAudio);
//         if (index != -1) {
//             this._playingAudios.splice(index, 1);
//         }
//     }
//     addPlaying(oneShotAudio) {
//         this._playingAudios.push(oneShotAudio);
//     }
//     discardOnePlayingIfNeeded() {
//         if (this._playingAudios.length < this.maxAudioChannel) {
//             return
//         }
        
//         let removed = this._playingAudios.splice(0, 1)[0];
//         removed?.stop();
//     }

//     //使用 AudioSource.play() 播放的音频
//     addPlayer (player) {
//         let index = this._players.indexOf(player);
//         if (index == -1) {
//             this._players.push(player);
//             return true;
//         }
//         return false;
//     }

//     removePlayer(player) {
//         let index = this._players.indexOf(player);
//         if (index != -1) {
//             this._players.splice(index, 1);
//         }
//     }

//     //超出上限时，停止一个，循环音效不给停止
//     discardOnePlayerIfNeeded() {
//         if (this._players.length < this.maxAudioChannel) {
//             return
//         }
//         this._players.forEach((player) => {
//             if (!player.loop) {
//                 player.stop();
//                 this.removePlayer(player);
//                 return;
//             }
//         });
//     }
// }

// let audioManager = new PolyfillAudioManager();
// cc.AudioSource.prototype.playOneShot = function (clip, volumeScale = 1) {
//     if (!clip._nativeAsset) {
//         console.error("Invalid audio clip");
//         return;
//     }
//     let AudioPlayer = Object.getPrototypeOf(clip._nativeAsset.player).constructor;

//     //支持返回音效，进行暂停等操作
//     return new Promise((s, r) => {
//         AudioPlayer.loadOneShotAudio(clip._nativeAsset.url, this._volume * volumeScale, {

//             audioLoadMode: clip.loadMode,
    
//         }).then((oneShotAudio) => {
//             //@ts-ignore
//             audioManager.discardOnePlayingIfNeeded();
//             oneShotAudio.onPlay = () => {
//                 audioManager.addPlaying(oneShotAudio);
//             };
//             oneShotAudio.onEnd = () => {
//                 audioManager.removePlaying(oneShotAudio);
//             };
//             if (WECHAT && MINIGAME) {
//                 // @ts-ignore
//                 if (oneShotAudio._audio && oneShotAudio._audio._innerAudioContext) {
//                     // @ts-ignore
//                     oneShotAudio._audio._innerAudioContext.onStop(() => {
//                         // @ts-ignore
//                         if (oneShotAudio._audio._innerAudioContext) {
//                             // @ts-ignore
//                             oneShotAudio._audio._innerAudioContext.destroy();
//                         }
//                         audioManager.removePlaying(oneShotAudio);
//                         // @ts-expect-error Type 'null' is not assignable to type 'InnerAudioContext'.
//                         oneShotAudio._audio._innerAudioContext = null;
//                     });
//                 } else {
//                     // @ts-ignore
//                     console.warn("oneShotAudio._audio:" + oneShotAudio._audio);
//                     // @ts-ignore
//                     console.warn("oneShotAudio._audio?._innerAudioContext:" + oneShotAudio._audio?._innerAudioContext);
//                 }
//             }
//             oneShotAudio.play();

//             s(oneShotAudio);
//         }).catch((e) => {
//             console.error(e)
//         });
//     })
// };

// ==============================================================================
// 扩展String
// ==============================================================================

/**
 * string格式化
 * @param args
 * @returns {String}
 * @example:
     var template1="我是{0}，今年{1}了";
     var template2="我是{name}，今年{age}了";
     var result1=template1.format("loogn",22);
     var result2=template2.format({name:"loogn",age:22});
 */
String.prototype.format = function (args) {
    var result = this;
    if (arguments.length > 0) {
        if (arguments.length == 1 && typeof (args) == "object") {
            for (var key in args) {
                if (args[key] != undefined) {
                    var reg = new RegExp("(\\{" + key + "\\})", "g");
                    //result = result.replace(reg, "\"" + args[key] + "\"");
                    result = result.replace(reg, args[key]);
                }
            }
        } else {
            for (var i = 0; i < arguments.length; i++) {
                var re = new RegExp('\\{' + (i) + '\\}', 'g');
                //result = result.replace(re, "\"" + arguments[i] + "\"");
                result = result.replace(re, arguments[i]);
            }
        }
    }
    return result;
};

// cc.NodeEventProcessor.prototype.__ggHandleEventTouch = cc.NodeEventProcessor.prototype._handleEventTouch;
// cc.NodeEventProcessor.prototype._handleEventTouch = function (eventTouch) {
//   if (this.node.getComponent(cc.UITransformComponent).getBoundingBoxToWorld().contains(eventTouch.getUILocation())) {
//       if (!cc.macro.ENABLE_MULTI_TOUCH) {
//       // 开启单点
//       if (gg.__curTouchTarget && gg.__curTouchTarget != this.node) {
//         gg.warn(`单点开启，已触摸${gg.__curTouchTarget.name}，触摸${this.node.name}无效。`);
//         return false;
//       } else {
//         gg.__curTouchTarget = this.node;
//       }
//     }

//     switch (eventTouch.type) {
//       case cc.Node.EventType.TOUCH_START:
//         return this._handleTouchStart(eventTouch);
//       case cc.Node.EventType.TOUCH_MOVE:
//         return this._handleTouchMove(eventTouch);
//       case cc.Node.EventType.TOUCH_END:
//         gg.__curTouchTarget = undefined; // touch结束，置空
//         return this._handleTouchEnd(eventTouch);
//       case cc.Node.EventType.TOUCH_CANCEL:
//         gg.__curTouchTarget = undefined; // touch失效，置空
//         return this._handleTouchCancel(eventTouch);
//       default:
//         return false;
//     }
//   }
// };



if (gg.isH5) { gg.warn = (...argv) => { console.log('%c' + argv, 'color:#ff85ff'); }; }